<template>
	<div class="form-file-upload">
		<div class="upload-label" :class="{ required }">{{ label }}</div>
		<div class="upload-wrap">
			<van-uploader
				:readonly="readonly"
				v-model="innerFiles"
				:max-count="maxCount"
				:disabled="disabled"
				:deletable="!readonly"
				:show-upload="!readonly"
				:after-read="handleAfterRead"
				multiple
				@delete="handleDelete"
			/>
			<!-- Fallback 图片预览：若 van-uploader 未正确显示缩略图，则此处保证展示 -->
			<div v-if="showPreviewFallback && innerFiles.length" class="fallback-grid">
				<div class="fb-item" v-for="f in innerFiles" :key="f.id || f.url" v-show="f.isImage">
					<img :src="f.url" :alt="f.name" crossorigin="anonymous" @error="onImgError(f)" />
					<div class="fb-name" :title="f.name">{{ f.name }}</div>
				</div>
			</div>
			<!-- 可选显示文件 URL 列表（只读展示） -->
			<div v-if="showUrl && innerFiles.length" class="file-url-list">
				<div class="file-url-item" v-for="f in innerFiles" :key="f.id || f.url">
					<span class="file-name" :title="f.fileName">{{ f.fileName }}</span>
					<a class="file-link" :href="f.url" target="_blank">{{ f.url }}</a>
				</div>
			</div>
		</div>
	</div>
</template>

<script>
import { ref, watch, onMounted } from 'vue'
import { showToast } from 'vant'
import { uploadFileUrl, post } from '@/api'
import axios from 'axios'

export default {
	name: 'FormFileUpload',
	props: {
		modelValue: {
			type: Array,
			default: () => [],
		},
		label: {
			type: String,
			default: '附件信息',
		},
		required: {
			type: Boolean,
			default: false,
		},
		disabled: {
			type: Boolean,
			default: false,
		},
		readonly: {
			type: Boolean,
			default: false,
		},
		maxCount: {
			type: Number,
			default: 6,
		},
		// 主业务ID
		businessId: {
			type: String,
			default: '',
		},
		bigType: {
			type: String,
			default: '',
		},
		smallType: {
			type: String,
			default: '',
		},
		// 是否在上传组件下方显示 URL 与名称
		showUrl: {
			type: Boolean,
			default: false,
		},
	},
	emits: ['update:modelValue', 'upload', 'change'],
	setup(props, { emit }) {
		const innerFiles = ref(props.modelValue.map((f) => ({ id: f.id, url: f.url, fileName: f.name, status: 'done' })))

		// 合并文件列表避免重复
		const mergeFileList = (orig, add) => {
			const map = new Map()
			orig.forEach((f) => map.set(f.id || f.url, f))
			add.forEach((f) => {
				const key = f.id || f.url
				if (!map.has(key)) map.set(key, f)
			})
			return Array.from(map.values())
		}

		watch(
			() => props.modelValue,
			(nv) => {
				innerFiles.value = nv.map((f) => ({ id: f.id, url: f.url, fileName: f.name, status: 'done' }))
			}
		)

		// 回显文件
		const queryFiles = async () => {
			if (!props.businessId) return
			try {
				const res = await post('/api/upload/list', { businessId: props.businessId })
				if (res.code === '0' && Array.isArray(res.data)) {
					const list = res.data.map((it) => ({ id: it.id, url: it.url, fileName: it.originalFileName || it.fileName || it.name, status: 'done' }))
					innerFiles.value = mergeFileList(innerFiles.value, list)
					console.log('回显文件列表:', innerFiles.value)
					emitValue()
				}
			} catch (e) {
				console.error('回显文件失败', e)
			}
		}

		watch(
			() => props.businessId,
			(nv, ov) => {
				if (nv && nv !== ov) queryFiles()
			}
		)
		onMounted(() => queryFiles())

		const doUpload = async (file) => {
			const form = new FormData()
			form.append('file', file.file)
			// 业务主键：后端有的使用 ywid，有的使用 businessId，这里同时传递，提升兼容性
			if (props.businessId) {
				form.append('businessId', props.businessId)
				form.append('ywid', props.businessId) // 兼容旧字段
			}
			if (props.bigType) form.append('bigType', props.bigType)
			if (props.smallType) form.append('smallType', props.smallType)
			try {
				const res = await axios.post(uploadFileUrl, form, { headers: { 'Content-Type': 'multipart/form-data' } })
				if (res.data?.code === '0') {
					const uploaded = res.data.data || {}
					// 规范化返回：填补缺失字段，确保后续回显及去重
					if (!uploaded.id) uploaded.id = 'F_' + Date.now() + '_' + Math.random().toString(16).slice(2)
					if (!uploaded.url && uploaded.path) uploaded.url = uploaded.path
					return uploaded // 约定返回文件对象 { id, url, name, ... }
				}
				throw new Error(res.data?.msg || '上传失败')
			} catch (e) {
				console.error(e)
				showToast('上传失败')
				throw e
			}
		}

		const handleAfterRead = async (file) => {
			const files = Array.isArray(file) ? file : [file]
			for (const f of files) {
				f.status = 'uploading'
				try {
					const uploaded = await doUpload(f)
					f.status = 'done'
					f.url = uploaded.url || uploaded.path
					f.id = uploaded.id
					f.fileName = uploaded.originalFileName || uploaded.fileName || uploaded.name || f.file?.name
				} catch (e) {
					f.status = 'failed'
				}
			}
			emitValue()
		}

		const handleDelete = async (e) => {
			const idx = e.index
			const target = innerFiles.value[idx]
			if (target?.id) {
				try {
					await post('/api/upload/delete', { id: target.id })
				} catch (err) {
					console.error('删除文件失败', err)
					showToast('删除失败')
				}
			}
			innerFiles.value.splice(idx, 1)
			emitValue()
		}

		const emitValue = () => {
			const out = innerFiles.value.map((f) => ({ id: f.id, url: f.url, name: f.fileName }))
			emit('update:modelValue', out)
			emit('change', out)
			emit('upload', out)
		}
		return { innerFiles, handleAfterRead, handleDelete }
	},
}
</script>

<style lang="less" scoped>
.form-file-upload {
	width: 100%;
	background: #fff;
	padding: 0 8px;
	margin: 10px 0;
}
.upload-label {
	font-size: 14px;
	color: #333;
	padding: 10px 0;
}
.upload-wrap {
	width: 100%;
	background: #fff;
}
.file-url-list {
	margin-top: 8px;
	max-height: 160px;
	overflow-y: auto;
	background: #fafafa;
	border: 1px solid #eee;
	padding: 6px 8px;
	border-radius: 4px;
}
.file-url-item {
	font-size: 11px;
	line-height: 1.6;
	display: flex;
	flex-direction: column;
	margin-bottom: 4px;
}
.file-url-item:last-child {
	margin-bottom: 0;
}
.file-name {
	color: #666;
	font-weight: 600;
}
.file-link {
	color: #1989fa;
	word-break: break-all;
	text-decoration: none;
}
.file-link:hover {
	text-decoration: underline;
}
</style>